//
//  AlgorithmTest.m
//  iBeaconDemo
//
//  Created by cry on 17/1/20.
//  Copyright © 2017年 eGova. All rights reserved.
//

#import "AlgorithmHelper.h"
#import "TTReceiver.h"
#import "TTBeaconRegion.h"
#import "TTRSSITool.h"
#import "TTRoomMap.h"
#import "TTProbabilityBasedAlgorithm.h"
#import "TTKalmanFilter.h"

static int A = 60; // 功率
static double n = 6; // 衰减因子

@interface AlgorithmHelper()

@property (nonatomic, strong) NSMutableArray<TTReceiver *> *receivers;
@property (nonatomic, strong) NSMutableArray<CLBeacon *> *beacons;
@property (nonatomic, strong) NSMutableDictionary<NSString *, NSNumber *> *readings;
@property (nonatomic, strong) NSMutableDictionary<NSString *, NSNumber *> *rdMap;
@property (nonatomic, strong) TTKalmanFilter *filter;
@property (nonatomic, copy)   NSString *floorName;

@end

@implementation AlgorithmHelper{
    double _minX;
    double _maxX;
    double _minY;
    double _maxY;
}

+ (void)test{
    // 算法测试
    [[[AlgorithmHelper alloc] init] calculate];
}

+ (TTPoint *)testWithBeacons:(NSArray *)beacons{
    AlgorithmHelper *test = [[AlgorithmHelper alloc] init];
    test.beacons = [NSMutableArray arrayWithArray:beacons];
    return [test calculate];
}

+ (TTPoint *)helpWithBeacons:(NSArray *)beacons
                   receivers:(NSMutableArray *)receivers{
    AlgorithmHelper *test = [[AlgorithmHelper alloc] init];
    test.beacons = [NSMutableArray arrayWithArray:beacons];
    test.receivers = receivers;
    return [test calculate];
}

- (TTPoint *)calculate{
    self.floorName = [self getFloorName];
    NSMutableArray<TTBeaconRegion *> *ibeacons = [self getBeaconRegions];
    [ibeacons sortUsingSelector:@selector(compareByRSSI:)];
    // 少于三个点，按信号强度获取坐标点
    if (ibeacons.count < 3) {
        TTBeaconRegion *beacon = ibeacons.firstObject;
        for (TTReceiver *receiver in self.receivers) {
            if ([receiver.keyID isEqualToString:beacon.keyID]) {
                TTPoint *point = [[TTPoint alloc] initWithX:receiver.xPos Y:receiver.yPos floorName:self.floorName];
                return point;
            }
        }
    }
    // 选出信号强度最强的5个点
    while (ibeacons.count > 5) {
        [ibeacons removeLastObject];
    }
    [self setupPropertyWithBeacons:ibeacons];
    
    TTRoomMap *roomMap = [[TTRoomMap alloc] initWithXFrom:_minX xTo:_maxX yFrom:_minY yTo:_maxY];
    TTProbabilityBasedAlgorithm *algo = [[TTProbabilityBasedAlgorithm alloc] initWithRoomMap:roomMap receivers:_receivers xFrom:_minX xTo:_maxX yFrom:_minY yTo:_maxY a:A n:n filter:_filter];
    TTPoint *p = [algo calculate:_readings];
    if (p) {
        p.floorName = _floorName;
        return p;
    }
    return nil;
}

- (void)setupPropertyWithBeacons:(NSMutableArray<TTBeaconRegion *> *)ibeacons{
    
    _readings = [NSMutableDictionary dictionary];
    _rdMap = [NSMutableDictionary dictionary];
    _filter = [[TTKalmanFilter alloc] init];
    
    for (TTBeaconRegion *beancon in ibeacons) {
        [_readings setValue:@(beancon.rssi) forKey:beancon.keyID];
    }
    for (TTBeaconRegion *beancon in ibeacons) {
        [_rdMap setValue:@([TTRSSITool getDistanceWithA:A n:n rssi:beancon.rssi])
                  forKey:beancon.keyID];
    }
    _minX = [TTRSSITool getMinXWithReceivers:_receivers readings:_readings rdMap:_rdMap];
    _maxX = [TTRSSITool getMaxXWithReceivers:_receivers readings:_readings rdMap:_rdMap];
    _minY = [TTRSSITool getMinYWithReceivers:_receivers readings:_readings rdMap:_rdMap];
    _maxY = [TTRSSITool getMaxYWithReceivers:_receivers readings:_readings rdMap:_rdMap];
}
- (NSString *)getFloorName{
    ///
    return nil;
}
/// 获取到的rssi值
- (NSMutableArray<TTBeaconRegion *> *)getBeaconRegions{

    NSMutableArray<TTBeaconRegion *> *beacons = [NSMutableArray array];
    for (CLBeacon *beacon in self.beacons) {
        if (beacon.proximity != CLProximityUnknown && beacon.rssi != 0) {
            
            [beacons addObject:[[TTBeaconRegion alloc] initWithName:@"Beacon"
                                                               uuid:beacon.proximityUUID
                                                              major:beacon.major.intValue
                                                              minor:beacon.minor.intValue
                                                               rssi:beacon.rssi]];
        }
    }
    return beacons;
    
}


- (double)distanceToRSSIWithDistance:(double)distance{
    return - (10 * n * log10(distance) + A);
}

@end
